/* Copyright (c) 2006, 2009, Carl Burch. License information is located in the
 * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
 
package com.cburch.draw.gui;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import com.cburch.draw.actions.ModelChangeAttributeAction;
import com.cburch.draw.canvas.AttributeMapKey;
import com.cburch.draw.canvas.Canvas;
import com.cburch.draw.canvas.CanvasModel;
import com.cburch.draw.canvas.CanvasObject;
import com.cburch.draw.canvas.SelectionEvent;
import com.cburch.draw.canvas.SelectionListener;
import com.cburch.draw.model.DrawingAttributeSet;
import com.cburch.draw.tools.AbstractTool;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeEvent;
import com.cburch.logisim.data.AttributeListener;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.AttributeSets;
import com.cburch.logisim.gui.main.AttributeTable;
import com.cburch.logisim.gui.main.AttributeTableListener;

public class AttributeManager
        implements AttributeTableListener, SelectionListener, AttributeListener,
            PropertyChangeListener {
    private Canvas canvas;
    private AttributeTable table;
    private DrawingAttributeSet generalAttrs;
    private AttributeSet attrs;
    private Set selected;
    
    public AttributeManager(Canvas canvas, AttributeTable table, DrawingAttributeSet attrs) {
        this.canvas = canvas;
        this.table = table;
        this.generalAttrs = attrs;
        
        canvas.getSelection().addSelectionListener(this);
        canvas.addPropertyChangeListener(Canvas.TOOL_PROPERTY, this);
    }

    public void valueChangeRequested(AttributeTable table, AttributeSet attrs,
            Attribute attr, Object value) {
        if(attrs == generalAttrs) {
            attrs.setValue(attr, value);
        } else if(attrs == this.attrs) {
            setSelectedValues(attr, value);
        }
    }
    
    public void selectionChanged(SelectionEvent e) {
        LinkedHashMap attrMap = new LinkedHashMap();
        selected = e.getSelection().getSelected();
        Iterator sit = selected.iterator();
        if(sit.hasNext()) {
            AttributeSet first = ((CanvasObject) sit.next()).getAttributeSet();
            for(Iterator ait = first.getAttributes().iterator(); ait.hasNext(); ) {
                Attribute attr = (Attribute) ait.next();
                attrMap.put(attr, first.getValue(attr));
            }
            while(sit.hasNext()) {
                AttributeSet next = ((CanvasObject) sit.next()).getAttributeSet();
                for(Iterator ait = next.getAttributes().iterator(); ait.hasNext(); ) {
                    Attribute attr = (Attribute) ait.next();
                    if(attrMap.containsKey(attr)) {
                        Object v = attrMap.get(attr);
                        if(v != null && !v.equals(next.getValue(attr))) {
                            attrMap.put(attr, null);
                        }
                    }
                }
            }
        }

        Attribute[] attrs = new Attribute[attrMap.size()];
        Object[] values = new Object[attrs.length];
        int i = 0;
        for(Iterator it = attrMap.entrySet().iterator(); it.hasNext(); i++) {
            Map.Entry entry = (Map.Entry) it.next();
            attrs[i] = (Attribute) entry.getKey();
            values[i] = entry.getValue();
        }
        AttributeSet set = AttributeSets.fixedSet(attrs, values);
        // set.addAttributeListener(this);
        table.setAttributeSet(set, this);
        this.attrs = set;
    }
    
    private void setSelectedValues(Attribute attr, Object value) {
        HashMap oldVals = new HashMap();
        HashMap newVals = new HashMap();
        for(Iterator it = selected.iterator(); it.hasNext(); ) {
            CanvasObject o = (CanvasObject) it.next();
            AttributeMapKey key = new AttributeMapKey(attr, o);
            oldVals.put(key, o.getAttributeSet().getValue(attr));
            newVals.put(key, value);
        }
        CanvasModel model = canvas.getModel();
        model.doAction(new ModelChangeAttributeAction(model, oldVals, newVals));
    }

    public void attributeListChanged(AttributeEvent e) { }

    public void attributeValueChanged(AttributeEvent e) {
        setSelectedValues(e.getAttribute(), e.getValue());
    }

    public void propertyChange(PropertyChangeEvent evt) {
        String prop = evt.getPropertyName();
        if(prop.equals(Canvas.TOOL_PROPERTY)) {
            Object tool = canvas.getTool();
            if(tool instanceof AbstractTool) {
                generalAttrs.setAttributes(((AbstractTool) tool).getAttributes());
                table.setAttributeSet(generalAttrs, this);
            } else {
                table.setAttributeSet(null, null);
            }
        }
    }
}
